package org.swim.web.servlet;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;

import org.apache.commons.lang.WordUtils;
import org.swim.remote.entities.IAbility;
import org.swim.remote.entities.IUser;
import org.swim.remote.exceptions.SwimException;
import org.swim.utils.SwimLog;
import org.swim.web.servlet.consts.Action;
import org.swim.web.servlet.consts.SearchAttr;
import org.swim.web.servlet.consts.SearchAttr.What;
import org.swim.web.utils.SwimConst;
import org.swim.web.utils.SwimUtils;

/**
 * Servlet implementation class Search
 */
public class SearchSL extends SwimServlet {

	private static final long serialVersionUID = 1L;

	/**
	 * @throws NamingException
	 * @see HttpServlet#HttpServlet()
	 */
	public SearchSL() {
		super();

	}

	protected void doRequest(HttpServletRequest request,
			HttpServletResponse response, Method method, Action action)
			throws ServletException, IOException {
		SwimLog.getSwimLog(SearchSL.class).debug(SearchSL.class,
				"Action requested: " + action);

		switch (action) {
		case AUTOCOMPLETEABILITY:
			autocompleteAbility(request, response);
			break;
		case AUTOCOMPLETENAME:
			autocompleteName(request, response);
			break;
		case FINDUSERS:
			// TODO FINDUSERS
			try {
				findUsers(request, response);
			} catch (SwimException e) {
				e.printStackTrace();
				catchSwimExcpetion(action, e, "/", request,
						response);
			} catch (NamingException e) {
				e.printStackTrace();
				catchGenericExcpetion(action, e, request, response);
			}
			break;

		default:
			response.sendRedirect(SwimConst.Url.HOME);
			break;
		}

	}

	private void autocompleteAbility(HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		String query = request.getParameter(SearchAttr.QUERY);

		// Request abilities
		JSONObject object = new JSONObject();
		object.accumulate("search-query", query);
		List<IAbility> abilities = getAmr().findAbilities(object);

		// Create JSONArray for response
		JSONArray result = new JSONArray();
		for (IAbility iAbility : abilities) {
			result.add(SwimUtils.capitalizeFirstChar(iAbility.getName()
					.toLowerCase()));
		}

		response.setContentType("text/x-json;charset=UTF-8");
		response.getOutputStream().print(result.toString());
	}

	private void autocompleteName(HttpServletRequest request,
			HttpServletResponse response) throws IOException {
		String query = request.getParameter(SearchAttr.QUERY);
		if (query == null || query.equals("")) {
			response.setContentType("text/x-json;charset=UTF-8");
			response.getOutputStream().print("[]");
			return;
		}

		// Request friends list
		JSONObject object = new JSONObject();
		object.accumulate("search-query", query);
		List<IUser> users = getUmr().findUsers(object);

		// Create JSON Array for response
		JSONArray result = new JSONArray();
		String fullname;
		IUser owner;
		try {
			owner = getUmr().getTokenOwner(getToken(request));
		} catch (SwimException e) {
			owner = null;
			e.printStackTrace();
		}

		for (IUser iUser : users) {
			fullname = iUser.getFullName();
			if (!iUser.equals(owner) && fullname != null
					&& !fullname.equals("")) {
				result.add(WordUtils.capitalize(iUser.getFullName()
						.toLowerCase()));
			}
		}

		response.setContentType("text/x-json;charset=UTF-8");
		response.getOutputStream().print(result.toString());
	}

	private void findUsers(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException,
			SwimException, NamingException {

		JSONObject jsonSearch = (JSONObject) JSONSerializer.toJSON(
				request.getParameterMap(), SearchAttr.JSONCFG);

		boolean friendInclude = true;
		boolean noFriendInclude = true;
		if (request.getParameter("filter") != null
				&& request.getParameter("filter").equals("friend"))
			friendInclude = false;
		else if (request.getParameter("filter") != null
				&& request.getParameter("filter").equals("nofriend"))
			noFriendInclude = false;

		if (SwimUtils.isLogged(request)) {
			// If user is logged advanced reasearch
			List<IUser> friends, noFriends;
			jsonSearch.accumulate("token", getToken(request));

			if (jsonSearch.containsKey("abilities")
					&& !jsonSearch.getJSONArray("abilities").isEmpty()) {
				if (friendInclude)
					friends = getUmr().findFriendsByAbility(jsonSearch);
				else
					friends = new ArrayList<IUser>();

				if (noFriendInclude)
					noFriends = getUmr().findNoFriendsByAbility(jsonSearch);
				else
					noFriends = new ArrayList<IUser>();

				jsonSearch.accumulate(SearchAttr.WHAT, What.ABILITY);

			} else if (!jsonSearch.getString("query").equals("")) {
				if (friendInclude)
					friends = getUmr().findFriendsByName(jsonSearch);
				else
					friends = new ArrayList<IUser>();

				if (noFriendInclude)
					noFriends = getUmr().findNoFriendsByName(jsonSearch);
				else
					noFriends = new ArrayList<IUser>();

				jsonSearch.accumulate(SearchAttr.WHAT, What.FRIEND);

			} else {
				friends = new ArrayList<IUser>();
				noFriends = new ArrayList<IUser>();
				jsonSearch.accumulate(SearchAttr.WHAT, What.FRIEND);
			}

			// Set all necessary attributes for jsp page
			request.setAttribute("search", jsonSearch);

			usersResult(friends, noFriends, request, response);

		} else {
			// If user is logged light reasearch
			jsonSearch.accumulate(SearchAttr.WHAT, What.ABILITY);
			request.setAttribute("search", jsonSearch);
			List<IUser> swimusers;
			if (jsonSearch.containsKey("abilities"))
				swimusers = getUmr().findUsersByAbilities(jsonSearch);
			else
				swimusers = new ArrayList<IUser>();
			usersResult(new ArrayList<IUser>(), swimusers, request, response);
		}

	}

	private void usersResult(List<IUser> friends, List<IUser> nofriends,
			HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		if (friends.size() + nofriends.size() == 1) {

			IUser user;
			if (friends.size() == 1)
				user = friends.get(0);
			else
				user = nofriends.get(0);

			request.getRequestDispatcher("/profile?who=" + user.getId())
					.forward(request, response);

		} else {
			request.setAttribute("friends", friends);
			request.setAttribute("nofriends", nofriends);

			request.getRequestDispatcher(JspPages.SEARCH).forward(request,
					response);
			// request.getRequestDispatcher(JspPages.SEARCH).forward(request,
			// response);
		}

	}

}
